/*
 * $Id: string_search.c,v 1.1 2005-09-17 11:12:03 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/mstring.h>
#else
#include <xp/bas/string.h>
#endif

xp_char_t* xp_strstr (const xp_char_t* str, const xp_char_t* sub)
{
	const xp_char_t* x, * y;

	y = sub;
	if (*y == XP_CHAR('\0')) return (xp_char_t*)str;

	while (*str != XP_CHAR('\0')) {
		if (*str != *y) {
			str++;
			continue;
		}

		x = str;
		while (xp_true) {
			if (*y == XP_CHAR('\0')) return (xp_char_t*)str;
			if (*x++ != *y++) break;
		}

		y = sub;
		str++;
	}

	return XP_NULL;
}

xp_char_t* xp_strxstr (
	const xp_char_t* str, xp_size_t size, const xp_char_t* sub)
{
	return xp_strxnstr (str, size, sub, xp_strlen(sub));
}

xp_char_t* xp_strxnstr (const xp_char_t* str,
	xp_size_t strsz, const xp_char_t* sub, xp_size_t subsz)
{
	const xp_char_t* end, * subp;

	if (subsz == 0) return (xp_char_t*)str;
	if (strsz < subsz) return XP_NULL;
	
	end = str + strsz - subsz;
	subp = sub + subsz;

	while (str <= end) {
		const xp_char_t* x = str;
		const xp_char_t* y = sub;

		while (xp_true) {
			if (y >= subp) return (xp_char_t*)str;
			if (*x != *y) break;
			x++; y++;
		}	

		str++;
	}
		
	return XP_NULL;
}

xp_char_t* xp_strrstr (const xp_char_t* str, const xp_char_t* sub)
{
	return xp_strxnrstr (str, xp_strlen(str), sub, xp_strlen(sub));
}

xp_char_t* xp_strxrstr (const xp_char_t* str, xp_size_t size, const xp_char_t* sub)
{
	return xp_strxnrstr (str, size, sub, xp_strlen(sub));
}

xp_char_t* xp_strxnrstr (
	const xp_char_t* str, xp_size_t strsz, const xp_char_t* sub, xp_size_t subsz)
{
	const xp_char_t* p = str + strsz;
	const xp_char_t* subp = sub + subsz;

	if (subsz == 0) return (xp_char_t*)p;
	if (strsz < subsz) return XP_NULL;

	p = p - subsz;

	while (p >= str) {
		const xp_char_t* x = p;
		const xp_char_t* y = sub;

		while (xp_true) {
			if (y >= subp) return (xp_char_t*)p;
			if (*x != *y) break;
			x++; y++;
		}	

		p--;
	}

	return XP_NULL;
}

xp_char_t* xp_strchr (const xp_char_t* str, xp_cint_t c)
{
	while (*str != XP_CHAR('\0')) {
		if (*str == c) return (xp_char_t*)str;
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strxchr (const xp_char_t* str, xp_size_t len, xp_cint_t c)
{
	const xp_char_t* end = str + len;
	while (str < end) {
		if (*str == c) return (xp_char_t*)str;
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strrchr (const xp_char_t* str, xp_cint_t c)
{
	const xp_char_t* end = str;
	while (*end != XP_CHAR('\0')) end++;
	while (end > str) {
		if (*--end == c) return (xp_char_t*)end;
	}
	return XP_NULL;
}

xp_char_t* xp_strxrchr (const xp_char_t* str, xp_size_t len, xp_cint_t c)
{
	const xp_char_t* end = str + len;
	while (end > str) {
		if (*--end == c) return (xp_char_t*)end;
	}
	return XP_NULL;
}

xp_char_t* xp_strpbrk (const xp_char_t* str, const xp_char_t* needle) 
{
	const xp_char_t* p;

	while (*str != XP_CHAR('\0')) {
		for (p = needle; *p != XP_CHAR('\0'); p++) {
			if (*p == *str) return (xp_char_t*)str;
		}
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strxpbrk (
	const xp_char_t* str, xp_size_t n, const xp_char_t* needle) 
{
	const xp_char_t* p;
	const xp_char_t* se = str + n;

	while (str < se) {
		for (p = needle; *p != XP_CHAR('\0'); p++) {
			if (*p == *str) return (xp_char_t*)str;
		}
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strnpbrk (
	const xp_char_t* str, const xp_char_t* needle, xp_size_t n) 
{
	const xp_char_t* p;
	const xp_char_t* ne = needle + n;

	while (*str != XP_CHAR('\0')) {
		for (p = needle; p < ne; p++) {
			if (*p == *str) return (xp_char_t*)str;
		}
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strxnpbrk (
	const xp_char_t* str, xp_size_t n1, const xp_char_t* needle, xp_size_t n2) 
{
	const xp_char_t* p;
	const xp_char_t* se = str + n1;
	const xp_char_t* ne = needle + n2;

	while (str < se) {
		for (p = needle; p < ne; p++) {
			if (*p == *str) return (xp_char_t*)str;
		}
		str++;
	}
	return XP_NULL;
}

xp_char_t* xp_strrpbrk (const xp_char_t* str, const xp_char_t* needle) 
{
	const xp_char_t* p;
	const xp_char_t* se = str;

	while (*se != XP_CHAR('\0')) se++;
	while (se > str) {
		xp_char_t c = *(--se);	
		for (p = needle; *p != XP_CHAR('\0'); p++) {
			if (*p == c) return (xp_char_t*)se;
		}
	}

	return XP_NULL;
}

xp_char_t* xp_strxrpbrk (
	const xp_char_t* str, xp_size_t n, const xp_char_t* needle) 
{
	const xp_char_t* p;
	const xp_char_t* se = str + n;

	while (se > str) {
		xp_char_t c = *(--se);
		for (p = needle; *p != XP_CHAR('\0'); p++) {
			if (*p == c) return (xp_char_t*)se;
		}
	}
	return XP_NULL;
}

xp_char_t* xp_strnrpbrk (
	const xp_char_t* str, const xp_char_t* needle, xp_size_t n) 
{
	const xp_char_t* p;
	const xp_char_t* ne = needle + n;
	const xp_char_t* se = str;

	while (*se != XP_CHAR('\0')) se++;
	while (se > str) {
		xp_char_t c = *(--se);
		for (p = needle; p < ne; p++) {
			if (*p == c) return (xp_char_t*)se;
		}
	}
	return XP_NULL;
}

xp_char_t* xp_strxnrpbrk (
	const xp_char_t* str, xp_size_t n1, 
	const xp_char_t* needle, xp_size_t n2) 
{
	const xp_char_t* p;
	const xp_char_t* se = str + n1;
	const xp_char_t* ne = needle + n2;

	while (se > str) {
		xp_char_t c = *(--se);
		for (p = needle; p < ne; p++) {
			if (*p == c) return (xp_char_t*)se;
		}
	}
	return XP_NULL;
}
 
xp_size_t xp_strspn (const xp_char_t* str1, const xp_char_t* str2)
{
	const xp_char_t* org = str1, * p;

	while (*str1 != XP_CHAR('\0')) {
		for (p = str2; *p != XP_CHAR('\0'); p++) {
			if (*str1 == *p) break;
		}
		if (*p == XP_CHAR('\0')) break;
		str1++;
	}

	return str1 - org;
}

xp_size_t xp_strxspn (
	const xp_char_t* str1, xp_size_t n1, const xp_char_t* str2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end = str1 + n1;

	while (str1 < end) {
		for (p = str2; *p != XP_CHAR('\0'); p++) {
			if (*str1 == *p) break;
		}
		if (*p == XP_CHAR('\0')) break;
		str1++;
	}

	return str1 - org;
}

xp_size_t xp_strnspn (
	const xp_char_t* str1, const xp_char_t* str2, xp_size_t n2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end = str2 + n2;

	while (*str1 != XP_CHAR('\0')) {
		for (p = str2; p < end; p++) {
			if (*str1 == *p) break;
		}
		if (*p == XP_CHAR('\0')) break;
		str1++;
	}

	return str1 - org;
}

xp_size_t xp_strxnspn (
	const xp_char_t* str1, xp_size_t n1, const xp_char_t* str2, xp_size_t n2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end1 = str1 + n1;
	const xp_char_t* end2 = str2 + n2;

	while (str1 < end1) {
		for (p = str2; p < end2; p++) {
			if (*str1 == *p) break;
		}
		if (*p == XP_CHAR('\0')) break;
		str1++;
	}

	return str1 - org;
}

xp_size_t xp_strcspn (const xp_char_t* str1, const xp_char_t* str2)
{
	const xp_char_t* org = str1, * p;

	while (*str1 != XP_CHAR('\0')) {
		for (p = str2; *p != XP_CHAR('\0'); p++) {
			if (*str1 == *p) goto xp_strcspn_exit;
		}
		str1++;
	}

xp_strcspn_exit:
	return str1 - org;
}

xp_size_t xp_strxcspn (
	const xp_char_t* str1, xp_size_t n1, const xp_char_t* str2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end = str1 + n1;

	while (str1 < end) {
		for (p = str2; *p != XP_CHAR('\0'); p++) {
			if (*str1 == *p) goto xp_strxcspn_exit;
		}
		str1++;
	}

xp_strxcspn_exit:
	return str1 - org;
}

xp_size_t xp_strncspn (
	const xp_char_t* str1, const xp_char_t* str2, xp_size_t n2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end = str2 + n2;

	while (*str1 != XP_CHAR('\0')) {
		for (p = str2; p < end; p++) {
			if (*str1 == *p) goto xp_strncspn_exit;
		}
		str1++;
	}

xp_strncspn_exit:
	return str1 - org;
}

xp_size_t xp_strxncspn (
	const xp_char_t* str1, xp_size_t n1, const xp_char_t* str2, xp_size_t n2)
{
	const xp_char_t* org = str1, * p;
	const xp_char_t* end1 = str1 + n1;
	const xp_char_t* end2 = str2 + n2;

	while (str1 < end1) {
		for (p = str2; p < end2; p++) {
			if (*str1 == *p) goto xp_strxncspn_exit;
		}
		str1++;
	}

xp_strxncspn_exit:
	return str1 - org;
}

